#include <string>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <windows.h>

class SdCard{
public:
    SdCard(char drive_letter);
    ~SdCard();

    void DisplayPartitionTable();
    
private:

    void ReadMbs();
    HANDLE device_;
    char buffer_[512];
    
private:
	//http://en.wikipedia.org/wiki/Master_boot_record#cite_note-6
	#pragma pack(push,1)
    struct PartitionTable {
	BYTE BootIndicator;
	BYTE StartingHead;
	WORD StartingSectorCylinder;
	BYTE SystemID;
	BYTE EndingHead;
	WORD EndSectorCylinder;
	DWORD RelativeSector;
	DWORD TotalSector;
    }pt_;
	#pragma pack(pop)
};
void SdCard::DisplayPartitionTable()
{
    PartitionTable* pt = (PartitionTable*)(buffer_ + 446);
	for(int i = 0; i < 4; ++i){
		std::cout << std::endl << "Partition " << i << std::endl;
   		WORD StartCylinder = ((pt->StartingSectorCylinder & 0xFF00) >> 8);
		StartCylinder |= ((pt->StartingSectorCylinder & 0x00C0) << 2); 
		
		WORD EndCylinder = ((pt->EndSectorCylinder & 0xFF00) >> 8);
		EndCylinder |= ((pt->EndSectorCylinder & 0x00C0) << 2);			
		
		std::cout << "BootIndicator:          " << std::hex << (long)pt->BootIndicator
				  << std::endl;
		std::cout << "SystemID:               " << std::hex << (long)pt->SystemID << std::endl;
		std::cout << "RelativeSector:         " << std::dec << pt->RelativeSector << std::endl;
		std::cout << "TotalSecotr:            " << std::dec << pt->TotalSector << std::endl;

		std::cout << "Start(C, H, S):         " << "(" << StartCylinder << " , " << std::dec << (long)pt->StartingHead
			<< " ," << std::dec << (pt->StartingSectorCylinder & 0x003F) <<")"
			<< std::endl; 

		std::cout << "End  (C, H, S):         " << "(" << EndCylinder << " , " << std::dec << (long)pt->EndingHead 
			<< " ," << (pt->EndSectorCylinder & 0x003F) << ")"
			<< std::endl;
		++pt;
	}
}

void SdCard::ReadMbs()
{
    DWORD cb;
    BOOL result = ::ReadFile(device_, buffer_, 512, &cb, 0);
    if(!result){
        throw "Fail to read the MBS";
    }
}

SdCard::SdCard(char drive_letter)
{
    std::string file_name("\\\\.\\");
    file_name += drive_letter;
    file_name += ":";
    
    HANDLE logic_file = CreateFile(file_name.c_str(),
               GENERIC_READ | GENERIC_WRITE,
               FILE_SHARE_READ | FILE_SHARE_WRITE,
               NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL);
    if( logic_file == INVALID_HANDLE_VALUE){
        throw "Unable to open the drive";
    }
    DWORD cb;
    STORAGE_DEVICE_NUMBER sdn;
    
    DWORD fResult = DeviceIoControl(logic_file,
                                    IOCTL_STORAGE_GET_DEVICE_NUMBER,
                                    0, 0, &sdn, sizeof(sdn), &cb, 0);
    if (!fResult){
        throw "Fail to get the phsical drive";
    }

    std::ostringstream oss;
    oss << "\\\\.\\PhysicalDrive";
    oss << sdn.DeviceNumber;
    device_ = ::CreateFile(oss.str().c_str(),
                           GENERIC_READ | GENERIC_WRITE,
                           FILE_SHARE_READ | FILE_SHARE_WRITE,
                           NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL);
    if(device_ == INVALID_HANDLE_VALUE){
        throw "Fail to open the device";
    }
    ReadMbs();
    
}
SdCard::~SdCard()
{
    if(device_ != INVALID_HANDLE_VALUE){
        ::CloseHandle(device_);
    }
}


int main()
{
    try{
        SdCard sd('g');
        sd.DisplayPartitionTable();
        
    }
    catch(std::string& ex){
        std::cout << ex << std::endl;
    }
	system("PAUSE");
    
}
